﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleScript
{
    internal class Parser
    {
        public List<Token> TokenList { set; get; }
        public Token? Token { set; get; }
        public int Position { set; get; }

        public Parser(List<Token> tokenList)
        {
            TokenList = tokenList;
            Position = 0;
        }

        public List<Statement> StatementList
        {
            get
            {
                List<Statement> statementList = new();
                while (true)
                {
                    Statement? statement = NextStatement;
                    if (statement == null)
                    {
                        break;
                    }
                    statementList.Add(statement);
                }
                return statementList;
            }
        }

        public Statement? NextStatement
        {
            get
            {
                ReadToken();
                if (Token == null)
                {
                    return null;
                }
                else
                {
                    Statement? statement;
                    if (IsLiteral(Token.LexicalType))
                    {
                        statement = NextLiteral;
                    }
                    else if (IsKeyword(Token.Literal))
                    {
                        statement = NextCall;
                    }
                    else
                    {
                        if (NextToken?.LexicalType == LexicalType.Equ)
                        {
                            statement = NextExpression;
                        }
                        else if (NextToken == null || NextToken.Line > Token.Line)
                        {
                            statement = NextIdentifier;
                        }
                        else
                        {
                            throw new Exception($"[Line:{Token.Line},Column:{Token.Column}]=>[{Token.Literal}]语法错误");
                        }
                    }

                    return statement;
                }

            }
        }

        public void ReadToken()
        {
            if (Position < TokenList.Count)
            {
                Token = TokenList[Position];
                Position++;
            }
            else
            {
                Token = null;
            }
        }

        public Token? NextToken
        {
            get
            {
                if (Position < TokenList.Count)
                {
                    return TokenList[Position];
                }
                else
                {
                    return null;
                }
            }
        }

        public static bool IsLiteral(LexicalType lexicalType)
        {
            return lexicalType >= LexicalType.LInt && lexicalType <= LexicalType.LString;
        }

        public static bool IsIdentifier(LexicalType lexicalType)
        {
            return lexicalType == LexicalType.Identifier;
        }

        public static bool IsKeyword(string identifier)
        {
            return Lexer.IsKeyword(identifier);
        }

        public static bool IsOperator(LexicalType lexicalType)
        {
            return lexicalType >= LexicalType.Add && lexicalType <= LexicalType.Mod;
        }

        public Literal? NextLiteral
        {
            get
            {
                Literal? statement = (Token?.LexicalType) switch
                {
                    LexicalType.LInt => new Int(),
                    LexicalType.LFloat => new Float(),
                    LexicalType.LString => new String(),
                    _ => null,
                };
                if (statement == null)
                {
                    return null;
                }
                statement.Result = Token;
                return statement;
            }
        }

        public Call? NextCall
        {
            get
            {
                Call? statement = new()
                {
                    Function = Token
                };
                int? line = Token?.Line;
                while (true)
                {
                    Token? nextToken = NextToken;
                    if (nextToken == null || nextToken.Line > line)
                    {
                        break;
                    }

                    if (IsLiteral(nextToken.LexicalType) || IsIdentifier(nextToken.LexicalType))
                    {
                        statement.ParameterList.Add(nextToken);
                    }
                    ReadToken();
                }
                return statement;
            }
        }

        public Identifier? NextIdentifier
        {
            get
            {
                Identifier? statement = new()
                {
                    Result = Token
                };
                return statement;
            }
        }

        public Expression? NextExpression
        {
            get
            {
                Expression? statement = new()
                {
                    Result = Token
                };
                int? line = Token?.Line;

                ReadToken();
                while (true)
                {
                    Token? nextToken = NextToken;
                    if (nextToken == null || nextToken.Line > line) { break; }
                    ReadToken();
                    if (IsOperator(nextToken.LexicalType))
                    {
                        statement.OperatorList.Add(nextToken);
                    }
                    else
                    {
                        statement.OperandList.Add(nextToken);
                    }
                }

                return statement;
            }
        }
    }
}
